<?php

namespace App\Services;

use App\Models\Menu;
use App\Models\Role as RoleModel;
use Illuminate\Support\Facades\DB;

/**
 * Class Role 角色业务类
 * @package App\Service
 */
class Role extends BaseService
{
    /**
     * RoleService constructor.
     */
    public function __construct()
    {
        $this->model = new \App\Models\Role();
    }

    /**
     * getDetailById 角色详情
     * @param int $id
     * @return array
     * @throws \Exception
     */
    public function getDetailById(int $id): array
    {
        $result = parent::getDetailById($id);
        if ($result) {
            // 角色拥有的菜单列表
            $menu_ids = \App\Models\Role::find($id)->menus;
            if ($menu_ids) {
                $result['menu_ids'] = array_column($menu_ids->toArray(), 'id');
            } else {
                $result['menu_ids'] = [];
            }
        }

        return $result;
    }

    /**
     * insertData 新增角色
     * @param array $data
     * @return bool
     * @throws \Exception
     */
    public function insertData(array $data): bool
    {
        DB::beginTransaction();
        try {
            parent::insertData($data);
            // 菜单-角色关系新增
            if (!empty($data['menu_ids'])) {
                foreach ($data['menu_ids'] as $menu_id) {
                    if (empty(Menu::find($menu_id))) {
                        DB::rollBack();

                        throw new \Exception('菜单id为' . $menu_id . '不存在');
                    }
                }
                \App\Models\Role::find($this->model->id)->menus()->attach($data['menu_ids']);
            }
        } catch (\Exception $exception) {
            DB::rollBack();

            throw new \Exception($exception->getMessage());
        }
        DB::commit();

        return true;
    }

    /**
     * updateData 更新角色
     * @param int $id
     * @param array $data
     * @return bool
     * @throws \Exception
     */
    public function updateData(int $id, array $data): bool
    {
        DB::beginTransaction();
        try {
            parent::updateData($id, $data);
            // 菜单-角色关系更新
            if (!empty($data['menu_ids'])) {
                foreach ($data['menu_ids'] as $menu_id) {
                    if (empty(Menu::find($menu_id))) {
                        DB::rollBack();

                        throw new \Exception('菜单id为' . $menu_id . '不存在');
                    }
                }
            }
            \App\Models\Role::find($id)->menus()->sync($data['menu_ids']);
        } catch (\Exception $exception) {
            DB::rollBack();

            throw new \Exception($exception->getMessage());
        }
        DB::commit();

        return true;
    }

    /**
     * getRoleSecondMenus 获取用户拥有的二级菜单
     * @param int $id
     * @return array
     */
    public function getRoleSecondMenus(int $id)
    {
        // 获取用户拥有的所有二级菜单
        $menu_ids = DB::table('menu_role')->where('role_id',$id)->pluck('menu_id')->toArray();
        $children_menus = \App\Models\Menu::whereIn('id', $menu_ids)->get(['id', 'pid', 'level', 'icon', 'name', 'title', 'url', 'controller', 'hidden', 'redirect'])->toArray();
        // 获取父级菜单
        $parent_menus = [];
        foreach ($menu_ids as $menu_id) {
            $menu = \App\Models\Menu::find($menu_id)->ancestors->toArray();
            if (empty($parent_menus)) {
                $parent_menus = $menu;
            } else {
                $parent_menus = array_merge($parent_menus, $menu);
            }
        }
        if (!empty($parent_menus)) {
            // 过滤重复的数组
            foreach ($parent_menus as $key => $value) {
                if (isset($out[$value['id']])) {
                    unset($parent_menus[$key]);
                } else {
                    $out[$value['id']] = $value;
                }
            }
        }
        $menus = array_merge($children_menus, array_values($parent_menus));
        $result = [];
        if (!empty($menus)) {
            foreach ($menus as $key => $value) {
                if ($menus[$key]['level'] == 2) {
                    $result[$key] = $menus[$key];
                }
            }
            $result = array_values($result);
        }

        return $result;
    }

    public function getRolePermissions(int $role_id, int $menu_id)
    {
        // 对应菜单所有节点
        $result['permissions'] = \App\Models\Permission::where('menu_id', $menu_id)->get()->toArray();
        // 角色已选中菜单下的节点
        $result['select'] = \App\Models\Role::find($role_id)->permissions()->where(['menu_id' => $menu_id])->get()->toArray();
        if (!empty($result['select'])) {
            $result['select'] = array_column($result['select'], 'id');
        }
        // 未选中的节点
        // $result['unselect'] = getDyaicArrayDiff($permissions, $result['select']);
        return $result;
    }

    /**
     * saveRolePermission 保存角色拥有的节点
     * @param array $data
     * @return bool
     * @throws \Exception
     */
    public function saveRolePermission(array $data): bool
    {
        try {
            // 获取角色原有的所有节点
            $allPermissions = \App\Models\Role::find($data['role_id'])->permissions()->get(['id'])->toArray();
            if ($allPermissions) {
                $allPermissions = array_column($allPermissions, 'id');
            }
            // 获取用户菜单下原有的所有节点
            $menuPermissions = \App\Models\Role::find($data['role_id'])->permissions()->where('menu_id', $data['menu_id'])->get(['id'])->toArray();
            if (!empty($menuPermissions)) {
                $menuPermissions = array_column($menuPermissions, 'id');
            }
            // 判断该菜单下是否原有的节点有减少
            $diff = array_values(array_diff($menuPermissions, $data['permission_id']));
            if (!empty($diff)) {
                // 去除被删除的节点
                $allPermissions = array_values(array_diff($allPermissions,$diff));
            }
            $permissions = array_unique(array_merge($allPermissions, $data['permission_id']));
            \App\Models\Role::find($data['role_id'])->permissions()->sync($permissions);
        } catch (\Exception $exception) {
            throw new \Exception($exception->getMessage());
        }

        return true;
    }
}
